
#include <algorithm>
#include "../util/util.h"
#include "target.h"
#include "module.h"

namespace STLF{

	class loop_per_thread_imp
	{
	public:
		loop_per_thread_imp():
			_thread(&msg_loop::run, &_msg_loop)
		{

		}

		msg_loop *get_msg_loop()
		{
			return &_msg_loop;
		}

		thread *get_thread()
		{
			return &_thread;
		}

		~loop_per_thread_imp()
		{
			_msg_loop.notify_quit();
                        _thread.join();

                        int test;
                        test = 1;
		}

	private:
		msg_loop _msg_loop;
        thread	_thread;
	};

	loop_per_thread::loop_per_thread():p_imp(new loop_per_thread_imp)
	{
		
	}

	loop_per_thread::~loop_per_thread()
	{
		delete p_imp;
	}

	msg_loop *loop_per_thread::get_msg_loop()
	{
		return p_imp->get_msg_loop();
	}

	thread *loop_per_thread::get_thread()
	{
		return p_imp->get_thread();
	}

	base_module::base_module(std::string name /* = */ ): _name(name)
	{
		get_s_module_list().push_back(this);
	}

	base_module::~base_module()
	{
		std::map<thread*, msg_loop*>::iterator it_mlm	= _msg_loop_map.begin();
		for (;it_mlm != _msg_loop_map.end(); ++it_mlm)
        {//must notify stop and join, but put join in next for loop because it more effective.
			it_mlm->second->notify_quit();
            //it_mlm->first->join();
		}
		it_mlm	= _msg_loop_map.begin();
		for (;it_mlm != _msg_loop_map.end(); ++it_mlm)
		{	
			it_mlm->first->join();
			delete it_mlm->first;
		}

		for (std::list<msg_loop*>::iterator il = _msg_loop_mgr.begin(); 
			il != _msg_loop_mgr.end(); ++il)
		{
			delete (*il);
		}
		
		get_s_module_list().remove(this);
	}

	msg_loop *base_module::create_msg_loop()
	{
		msg_loop *sp_msg_loop = new msg_loop;
		_msg_loop_mgr.push_back(sp_msg_loop);
		return sp_msg_loop;
	}	

	void base_module::destory_msg_loop(msg_loop *&pml)
	{
		list<msg_loop*>::iterator itf = std::find(_msg_loop_mgr.begin(), _msg_loop_mgr.end(), pml);
		if (itf != _msg_loop_mgr.end())
		{
			_msg_loop_mgr.remove(pml);
			//check if it attach a thread
			std::map<thread*, msg_loop*>::iterator it_mlm	= _msg_loop_map.begin();
			for (;it_mlm != _msg_loop_map.end(); ++it_mlm)
			{
				if (it_mlm->second == pml)
				{
					it_mlm->second->notify_quit();
					it_mlm->first->join();

					delete it_mlm->first;
					_msg_loop_map.erase(it_mlm);
					break;
				}
			}

			delete pml;
			pml = NULL;
		}
	}

	msg_loop *base_module::create_thread_msg_loop()
	{
		msg_loop *pmsg_loop = create_msg_loop();
		_add_thread(pmsg_loop);
		return pmsg_loop;
	}

	msg_loop *base_module::create_thread_msg_loop(target*ptar, unsigned int message,
		const any &wp, const any &lp)
	{
		msg_loop *pmsg_loop = create_msg_loop();
		pmsg_loop->link(ptar);
		_add_thread_with_loop_msg(pmsg_loop, 
			ptar->get_handle(), message, wp, lp);//t_msg
		return pmsg_loop;
	}

	void base_module::_add_thread(msg_loop *ploop)
	{
		if (ploop)
		{
			thread* pth = new thread(&msg_loop::run, ploop);
			_msg_loop_map[pth] = ploop;
		}
	}

	void base_module::_add_thread_with_loop_msg(msg_loop *ploop, 
		TARGET_HANDLE tar_handle, unsigned int message, 
		const any &wp, const any &lp)
	{
		if (ploop)
		{
			function<void()> thread_func = bind(&msg_loop::run_with_loop_msg, ploop, 
				tar_handle, message, wp, lp);

			thread* pth = new thread(thread_func);
			_msg_loop_map[pth] = ploop;
		}
	}

	list<base_module*> &base_module::get_s_module_list()
	{
		static list<base_module*> s_lm;
		return s_lm;
	}

}
